﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Skyhook.Core;

namespace Skyhook.Isometry
{
    internal class WorldTileMap
    {
        WorldTile[][] Tiles = null;
        int pWidth = 0;
        int pHeight = 0;
        int pObjectsCount = 0;

        public WorldTileMap(int width, int height)
        {
            if (width <= 0 || height <= 0)
            {
                throw new Exception("Incorrect tile map size (" + width.ToString() + " x " + height.ToString() + ")");
            }

            pWidth = width;
            pHeight = height;

            MapCreator<WorldTile> creator = new MapCreator<WorldTile>(pWidth,pHeight);
            Tiles = creator.Create();
        }

        public int Width
        {
            get
            {
                return pWidth;
            }
        }

        public int Height
        {
            get
            {
                return pHeight;
            }
        }

        private bool CheckCoordinates(float x, float y)
        {
            return BoundsChecker.IsPointInRect(new Point((int)x, (int)y), 
                new Rectangle(0, 0, pWidth, pHeight));
        }

        private void CorrectCoordinates(WorldPosition position)
        {
            position.Put(BoundsChecker.GetCorrectCoordinate(position.X, 0, pWidth),
                BoundsChecker.GetCorrectCoordinate(position.Y, 0, pHeight));
        }

        public void AddObject(WorldObject worldobject)
        {
            if (worldobject == null)
            {
                return;
            }

            WorldScreenPosition listener = worldobject.CreateScreenPosition();

            if (!CheckCoordinates(listener.X, listener.Y))
            {
                return;
            }

            int x = (int)listener.X;
            int y = (int)listener.Y;

            pObjectsCount -= Tiles[x][y].ObjectsCount;
            Tiles[x][y].AddOrReplaceEqualObject(worldobject);
            pObjectsCount += Tiles[x][y].ObjectsCount;
        }

        public void RemoveObject(WorldObject worldobject)
        {
            if (worldobject == null)
            {
                return;
            }

            WorldScreenPosition listener = worldobject.CreateScreenPosition();

            if (!CheckCoordinates(listener.X, listener.Y))
            {
                return;
            }

            int x = (int)listener.X;
            int y = (int)listener.Y;

            pObjectsCount -= Tiles[x][y].ObjectsCount;
            Tiles[x][y].RemoveObject(worldobject);
            pObjectsCount += Tiles[x][y].ObjectsCount;
        }

        public WorldObject GetObjectAtTile(int x, int y, int index)
        {
            if (!IsPointInBound(x, y))
            {
                return null;
            }

            return Tiles[x][y].GetObject(index);
        }

        public int GetObjectsCountAtTile(int x, int y)
        {
            if (!IsPointInBound(x,y))
            {
                return 0;
            }

            return Tiles[x][y].ObjectsCount;
        }

        private bool IsPointInBound(int x, int y)
        {
            return !(x < 0 || y < 0 || x >= pWidth || y >= pHeight);
        }

        public void UpdateObjectTile(WorldObject worldobject, WorldPosition position, Point point)
        {
            if (BoundsChecker.IsPointInRect(point,new Rectangle(0,0,pWidth,pHeight)))
            {
                Tiles[point.X][point.Y].RemoveObject(worldobject);
            }

            if (!CheckCoordinates(position.X,position.Y))
            {
                position.DisableEvents();
                CorrectCoordinates(position);
                position.EnableEvents();
            }

            int x = (int)position.X;
            int y = (int)position.Y;

            Tiles[x][y].AddObject(worldobject);
        }

        public int ObjectsCount
        {
            get
            {
                return pObjectsCount;
            }
        }
    }
}
